// phalanx reverse_iterator.hpp.cu header file

// Copyright (c) 2011 - 2011 Kohei Takahashi (Flast).
// Distributed under the MIT license. for more detail see COPYING.

// Redefinition C++03/0x STL reverse_iterator

#ifndef IG_PHALANX_ITERATOR_REVERSE_ITERATOR_HPP_CU_ONCE_
#define IG_PHALANX_ITERATOR_REVERSE_ITERATOR_HPP_CU_ONCE_

#include <phalanx/config.hpp.cu>

#include <iterator>

#include <phalanx/detail/retypedef.hpp.cu>

#include <phalanx/type_traits/common_type.hpp.cu>

namespace phalanx
{

template < typename _iterator >
struct reverse_iterator
  : public ::std::iterator<
      typename ::std::iterator_traits< _iterator >::iterator_category,
      typename ::std::iterator_traits< _iterator >::value_type,
      typename ::std::iterator_traits< _iterator >::difference_type,
      typename ::std::iterator_traits< _iterator >::pointer,
      typename ::std::iterator_traits< _iterator >::reference >
{
protected:
    _iterator current;

    typedef ::std::iterator_traits< _iterator > _traits_type;

public:
    typedef _iterator iterator_type;
    PHALANX_PP_RETYPEDEF( _traits_type, difference_type );
    PHALANX_PP_RETYPEDEF( _traits_type, pointer );
    PHALANX_PP_RETYPEDEF( _traits_type, reference );

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator()
      : current() {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    explicit
    reverse_iterator( iterator_type _x )
      : current( _x ) {}

    template < typename T >
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator( const reverse_iterator< T > &_x )
      : current( _x.current ) {}

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    iterator_type
    base( void ) const
    { return current; }

    // XXX: operator* does not use deref_tmp member to prevent from implicit
    //      performance regressions. Threfore some iterators may have defect
    //      with dereferencing.
    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reference
    operator*( void ) const
    {
        iterator_type _tmp = current;
        return *--_tmp;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    pointer
    operator->( void ) const
    { return &( operator*() ); }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator &
    operator++( void )
    {
        --current;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator
    operator++( int )
    {
        reverse_iterator _tmp = *this;
        --current;
        return _tmp;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator &
    operator--( void )
    {
        ++current;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator
    operator--( int )
    {
        reverse_iterator _tmp = *this;
        ++current;
        return _tmp;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator
    operator+( difference_type _n ) const
    { return reverse_iterator( current - _n ); }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator &
    operator+=( difference_type _n )
    {
        current -= _n;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator
    operator-( difference_type _n ) const
    { return reverse_iterator( current + _n ); }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reverse_iterator &
    operator-=( difference_type _n )
    {
        current += _n;
        return *this;
    }

    PHALANX_CONFIG_DEFAULT_FUNCTION( true )
    reference
    operator[]( difference_type _n ) const
    { return current[ -_n - 1 ]; }
};

template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
bool
operator==( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return _x.base() == _y.base(); }

template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
bool
operator<( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return _y.base() < _x.base(); }

template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
bool
operator!=( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return !( _x == _y ); }

template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
bool
operator>( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return _y < _x; }

template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
bool
operator>=( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return !( _y < _x ); }

template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
bool
operator<=( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return !( _x < _y ); }

// XXX: C++03 has no decltype expression.
template < typename _iterator_l, typename _iterator_r >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
typename common_type<
  typename reverse_iterator< _iterator_l >::difference_type,
  typename reverse_iterator< _iterator_r >::difference_type >::type
operator-( const reverse_iterator< _iterator_l > &_x,
  const reverse_iterator< _iterator_r > &_y )
{ return _y.base() - _x.base(); }

template < typename _iterator >
PHALANX_CONFIG_DEFAULT_FUNCTION( true )
reverse_iterator< _iterator >
operator+( typename reverse_iterator< _iterator >::difference_type _n,
  const reverse_iterator< _iterator > &_x )
{ return reverse_iterator< _iterator >( _x.base() - _n ); }

} // namespace phalanx

#endif // IG_PHALANX_ITERATOR_REVERSE_ITERATOR_HPP_CU_ONCE_

